package com.shop.front.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.query.MPJQueryWrapper;
import com.shop.common.config.GlobalConfig;
import com.shop.common.core.PageResult;
import com.shop.common.entity.Category;
import com.shop.common.entity.SearchRecord;
import com.shop.common.entity.course.Course;
import com.shop.common.entity.course.CourseAudience;
import com.shop.common.entity.course.CourseCollect;
import com.shop.common.entity.course.CourseHistory;
import com.shop.common.enums.CategoryTypeEnum;
import com.shop.common.exception.OperateException;
import com.shop.common.mapper.CategoryMapper;
import com.shop.common.mapper.SearchRecordMapper;
import com.shop.common.mapper.course.CourseAudienceMapper;
import com.shop.common.mapper.course.CourseCollectMapper;
import com.shop.common.mapper.course.CourseHistoryMapper;
import com.shop.common.mapper.course.CourseMapper;
import com.shop.common.util.ListUtils;
import com.shop.common.util.OSSUtil;
import com.shop.front.FrontThreadLocal;
import com.shop.front.service.ICourseService;
import com.shop.front.validate.common.PageValidate;
import com.shop.front.validate.course.CourseSearchValidate;
import com.shop.front.vo.course.CourseCategoryListedVo;
import com.shop.front.vo.course.CourseDetailVo;
import com.shop.front.vo.course.CourseListedVo;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class CourseServiceImpl implements ICourseService {
    @Resource
    CourseMapper courseMapper;

    @Resource
    CategoryMapper courseCategoryMapper;

    @Resource
    CourseCollectMapper courseCollectMapper;

    @Resource
    CourseHistoryMapper courseHistoryMapper;

    @Resource
    CourseAudienceMapper courseAudienceMapper;

    @Resource
    SearchRecordMapper searchRecordMapper;


    /**
     * 获取精选课程
     *
     * @return 精选课程列表
     */
    @Override
    public List<CourseListedVo> selected() {
        QueryWrapper<Course> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("selected", 1);
        queryWrapper.eq("is_delete", 0);
        // 观看对象是全部 或者是指定了当前用户为观看对象
        queryWrapper.and(i -> {
            i.eq("audience_type", 9).or().inSql("id", _inAudienceSql());
        });
        List<Course> courseListed = courseMapper.selectList(queryWrapper);
        return _courseListToCourseListedVo(courseListed);
    }

    /**
     * 获取课程列表
     *
     * @param searchValidate
     * @param pageValidate
     * @return 课程列表
     */
    @Override
    public PageResult<CourseListedVo> list(CourseSearchValidate searchValidate, PageValidate pageValidate) {
        Integer pageNo = pageValidate.getPageNo();
        Integer pageSize = pageValidate.getPageSize();
        QueryWrapper<Course> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_delete", 0);
        if (searchValidate.getCategoryId() != null) {
            queryWrapper.apply("find_in_set({0}, category_ids)", searchValidate.getCategoryId());
        }
        // 观看对象是全部 或者是指定了当前用户为观看对象
        queryWrapper.and(i -> {
            i.eq("audience_type", 9).or().inSql("id", _inAudienceSql());
        });

        String sort = searchValidate.getSort();
        List<String> sortFields = Arrays.asList("create_time", "id", "update_time", "study_count");
        if (sortFields.contains(sort)) {
            queryWrapper.orderByDesc(sort);
        }else queryWrapper.orderByDesc("id");

        courseMapper.setSearch(queryWrapper, searchValidate, new String[]{
            "like:keyword@title:str",
            "=:selected:int",
            "=:type:int"
        });
        // 如果有关键词则记录
        if(searchValidate.getKeyword() != null){
            QueryWrapper<SearchRecord> searchRecordQueryWrapper = new QueryWrapper<>();
            searchRecordQueryWrapper.eq("user_id", FrontThreadLocal.getUserId());
            searchRecordQueryWrapper.eq("keyword", searchValidate.getKeyword());
            searchRecordQueryWrapper.eq("is_delete", 0);
            searchRecordQueryWrapper.last("limit 1");
            SearchRecord searchRecord = searchRecordMapper.selectOne(searchRecordQueryWrapper);
            if(searchRecord == null){
                SearchRecord insert = new SearchRecord();
                insert.setUserId(FrontThreadLocal.getUserId());
                insert.setKeyword(searchValidate.getKeyword());
                insert.setCreateTime(System.currentTimeMillis()/1000);
                searchRecordMapper.insert(insert);
            }else{
                searchRecord.setUpdateTime(System.currentTimeMillis()/1000);
                searchRecord.setCount(searchRecord.getCount() + 1);
                searchRecordMapper.updateById(searchRecord);
            }
        }
        IPage<Course> iPage = courseMapper.selectPage(new Page<>(pageNo, pageSize), queryWrapper);
        return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), _courseListToCourseListedVo(iPage.getRecords()));
    }

    /**
     * 课程详情
     *
     * @param id
     */
    @Override
    public CourseDetailVo detail(Integer id) {
        Course course = courseMapper.selectById(id);
        if(course == null || course.getIsDelete() == 1){
            throw new OperateException("课程已下线");
        }

        if(course.getAudienceType() != 9) {
            // 判断是否指派了当前用户学习，如无则提示无权限查看
            QueryWrapper<CourseAudience> audienceQueryWrapper = new QueryWrapper<>();
            audienceQueryWrapper.eq("user_id", FrontThreadLocal.getUserId());
            audienceQueryWrapper.eq("course_id", id);
            audienceQueryWrapper.eq("is_delete", 0);
            audienceQueryWrapper.last("limit 1");
            CourseAudience courseAudience = courseAudienceMapper.selectOne(audienceQueryWrapper);
            Assert.notNull(courseAudience, "无权限查看");
        }

        CourseDetailVo courseDetailVo = new CourseDetailVo();
        BeanUtils.copyProperties(course, courseDetailVo);
        if(course.getCategoryIds() != null){
            List<Integer> categoryIds = ListUtils.stringToListAsInt(course.getCategoryIds(), ",");
            courseDetailVo.setCategoryIds(categoryIds);
            Map<Integer, CourseCategoryListedVo> categoryMap = categoryMap();
            List<CourseCategoryListedVo> categories = categoryIds.stream().map(categoryMap::get).collect(Collectors.toList());
            courseDetailVo.setCategories(categories);
        }
        if(course.getImages() != null){
            List<String> images = ListUtils.stringToListAsStr(course.getImages(), ",");
            List<String> completedImages = images.stream()
                    .map(image -> OSSUtil.completeUrl(image))
                    .collect(Collectors.toList());
            courseDetailVo.setImages(completedImages);
        }
        courseDetailVo.setCover(OSSUtil.completeUrl(course.getCover()));
        if(course.getVideo() != null){
            courseDetailVo.setVideo(OSSUtil.completeUrl(course.getVideo()));
        }

        // 如果有用户信息则添加学习记录
        courseDetailVo.setHistoryId(_addHistory(course));

        // 默认微收藏
        courseDetailVo.setCollected(0);

        // 如果是登录状态判断是否收藏
        String userId = FrontThreadLocal.getUserId();
        if(userId != null){
            QueryWrapper<CourseCollect> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", userId);
            queryWrapper.eq("course_id", id);
            queryWrapper.last("limit 1");
            CourseCollect courseCollect = courseCollectMapper.selectOne(queryWrapper);
            if(courseCollect != null){
                courseDetailVo.setCollected(1);
            }
        }
        return courseDetailVo;
    }

    /**
     * 上报学习状态
     */
    @Override
    public void report(Integer courseId, Integer historyId){
        String userId = FrontThreadLocal.getUserId();
        CourseHistory courseHistory = courseHistoryMapper.selectById(historyId);
        Assert.notNull(courseHistory, "数据不存在");
        Assert.isTrue(courseHistory.getUserId().equals(userId) && courseHistory.getCourseId() == courseId,
                "数据不存在");
        courseHistory.setUpdateTime(System.currentTimeMillis()/1000);
        courseHistory.setStudyTime(courseHistory.getUpdateTime() - courseHistory.getCreateTime());

        // 统计本课程累计学习时间
        QueryWrapper<CourseHistory> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("course_id", courseId);
        long totalTime = courseHistoryMapper.sumByLong("study_time", queryWrapper);
        courseHistory.setTotalTime(totalTime + courseHistory.getStudyTime());

        Course course = courseMapper.selectById(courseId);
        Assert.notNull(course, "课程不存在");
        if(courseHistory.getStudyTime() >= course.getTime()){
            courseHistory.setFinished(1);
        }
        courseHistoryMapper.updateById(courseHistory);
    }

    /**
     * 收藏课程
     *
     * @param id
     */
    @Override
    public void collect(Integer id) {
        // 获取用户类型和手机号
        String userId = FrontThreadLocal.getUserId();
        // 查询是否存在
        QueryWrapper<CourseCollect> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("course_id", id);
        CourseCollect courseCollectExist = courseCollectMapper.selectOne(queryWrapper);
        if (courseCollectExist != null) {
            throw new OperateException("已收藏");
        }
        // 添加收藏记录
        CourseCollect courseCollect = new CourseCollect();
        courseCollect.setCourseId(id);
        courseCollect.setUserId(userId);
        courseCollect.setCreateTime(System.currentTimeMillis()/1000);
        courseCollectMapper.insert(courseCollect);
    }

    /**
     * 取消收藏课程
     *
     * @param id
     */
    @Override
    public void cancelCollect(Integer id) {
        // 获取用户
        String userId = FrontThreadLocal.getUserId();
        // 查询是否存在
        QueryWrapper<CourseCollect> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("course_id", id);
        courseCollectMapper.delete(queryWrapper);
    }

    /**
     * 获取收藏课程分页
     *
     * @param pageValidate
     */
    @Override
    public PageResult<CourseListedVo> collected(PageValidate pageValidate) {
        return _joinPage("course_collect", pageValidate, false);
    }

    /**
     * 获取课程学习记录
     *
     * @param pageValidate
     */
    @Override
    public PageResult<CourseListedVo> history(PageValidate pageValidate) {
        return _joinPage("course_history", pageValidate, true);
    }


    private String _inAudienceSql(){
        return String.format("select course_id from %scourse_audience where user_id = '%s'",
                GlobalConfig.tablePrefix,
                FrontThreadLocal.getUserId());
    }

    /*
    * join查询课程列表，joinTable不需要前缀
    * 用户查询 收藏 历史记录等
     */
    public PageResult<CourseListedVo> _joinPage(String joinTable, PageValidate pageValidate, Boolean hasIsDelete){
        // 获取用户
        String userId = FrontThreadLocal.getUserId();

        Integer pageNo = pageValidate.getPageNo();
        Integer pageSize = pageValidate.getPageSize();

        MPJQueryWrapper<Course> queryWrapper = new MPJQueryWrapper<>();
        queryWrapper.orderByDesc("cc.id");
        queryWrapper.eq("cc.user_id", userId);
        List<String> onConditionList = new ArrayList<>();
        if(hasIsDelete){
            onConditionList.add("cc.is_delete = 0");
        }
        onConditionList.add("t.id = cc.course_id");
        StringBuilder joinSqlBuilder = new StringBuilder();
        joinSqlBuilder.append(GlobalConfig.tablePrefix);
        joinSqlBuilder.append(joinTable);
        joinSqlBuilder.append(" as cc on ");
        joinSqlBuilder.append(String.join(" and ", onConditionList));
        queryWrapper.innerJoin(joinSqlBuilder.toString());
        queryWrapper.select("t.id, t.title, t.cover, t.study_count, t.category_ids");
        IPage<Course> iPage = courseMapper.selectJoinPage(new Page<>(pageNo, pageSize), Course.class, queryWrapper);
        if(iPage.getRecords().size() == 0){
            return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), new ArrayList<>());
        }
        // 补充分类
        Map<Integer, CourseCategoryListedVo> categoryMap = categoryMap();
        List<CourseListedVo> list = new ArrayList<>();
        iPage.getRecords().forEach(course -> {
            CourseListedVo courseListedVo = new CourseListedVo();
            BeanUtils.copyProperties(course, courseListedVo);
            List<Integer> categoryIds = ListUtils.stringToListAsInt(course.getCategoryIds(), ",");
            courseListedVo.setCategoryIds(categoryIds);
            List<CourseCategoryListedVo> categories = categoryIds.stream().map(categoryMap::get).collect(Collectors.toList());
            courseListedVo.setCategories(categories);
            courseListedVo.setCover(OSSUtil.completeUrl(course.getCover()));
            list.add(courseListedVo);
        });
        return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), list);
    }

    /**
     * 清空历史记录
     *
     */
    @Override
    public void clearHistory() {
        // 获取用户类型和手机号
        String userId = FrontThreadLocal.getUserId();
        QueryWrapper<CourseHistory> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        CourseHistory update = new CourseHistory();
        update.setIsDelete(1);
        update.setDeleteTime(System.currentTimeMillis()/1000);
        courseHistoryMapper.update(update, queryWrapper);
    }

    /**
     * 课程分类
     */
    @Override
    public List<CourseCategoryListedVo> category(){
        List<Category> list = courseCategoryMapper.selectList(new QueryWrapper<Category>()
                .eq("is_delete", 0)
                .eq("type", CategoryTypeEnum.COURSE.getCode())
        );
        return list.stream().map(courseCategory -> {
            CourseCategoryListedVo courseCategoryListedVo = new CourseCategoryListedVo();
            BeanUtils.copyProperties(courseCategory, courseCategoryListedVo);
            courseCategoryListedVo.setCover(OSSUtil.completeUrl(courseCategory.getCover()));
            return courseCategoryListedVo;
        }).collect(Collectors.toList());
    }

    /**
     * 分类详情
     */
    @Override
    public CourseCategoryListedVo category(Integer id) {
        Category model = courseCategoryMapper.selectOne(
                new QueryWrapper<Category>()
                        .eq("id", id)
                        .eq("type", CategoryTypeEnum.COURSE.getCode())
                        .eq("is_delete", 0)
                        .last("limit 1"));

        Assert.notNull(model, "数据不存在");

        CourseCategoryListedVo vo = new CourseCategoryListedVo();
        BeanUtils.copyProperties(model, vo);
        vo.setCover(OSSUtil.completeUrl(model.getCover()));
        return vo;
    }

    /**
     * 添加课程学习记录
     */
    private Integer _addHistory(Course course){
        // 获取用户
        String userId = FrontThreadLocal.getUserId();
        if(userId == null){
            return null;
        }

        // 先查询是否有未删除的记录，如果有则更新时间，否则新增记录
        QueryWrapper<CourseHistory> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("course_id", course.getId());
        queryWrapper.eq("is_delete", 0);
        queryWrapper.orderByDesc("id");
        queryWrapper.last("limit 1");
        CourseHistory courseHistoryExist = courseHistoryMapper.selectOne(queryWrapper);
        if(courseHistoryExist != null){
            courseHistoryExist.setUpdateTime(System.currentTimeMillis() / 1000);
            courseHistoryMapper.updateById(courseHistoryExist);
            return courseHistoryExist.getId();
        }

        CourseHistory courseHistory = new CourseHistory();
        courseHistory.setCourseId(course.getId());
        courseHistory.setUserId(userId);
        courseHistory.setCreateTime(System.currentTimeMillis() / 1000);
        courseHistory.setUpdateTime(System.currentTimeMillis() / 1000);
        courseHistoryMapper.insert(courseHistory);

        // 学过的人数需要+1
        course.setStudyCount(course.getStudyCount() + 1);
        courseMapper.updateById(course);

        return courseHistory.getId();
    }

    /**
     * 获取分类Map
     */
    @Override
    public Map<Integer, CourseCategoryListedVo> categoryMap() {
        QueryWrapper<Category> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_delete", 0);
        List<Category> courseCategories = courseCategoryMapper.selectList(queryWrapper);
        Map<Integer, CourseCategoryListedVo> map = new HashMap<>();
        courseCategories.forEach(courseCategory -> {
            CourseCategoryListedVo courseCategoryListedVo = new CourseCategoryListedVo();
            BeanUtils.copyProperties(courseCategory, courseCategoryListedVo);
            map.put(courseCategory.getId(), courseCategoryListedVo);
        });
        return map;
    }

    /**
     * 将course转成CourseListedVo
     */
    private List<CourseListedVo> _courseListToCourseListedVo(List<Course> courseList){
        Map<Integer, CourseCategoryListedVo> categoryMap = categoryMap();
        return courseList
                .stream()
                .map(course -> {
                    CourseListedVo courseListedVo = new CourseListedVo();
                    BeanUtils.copyProperties(course, courseListedVo);
                    // 查询分类名称
                    if(course.getCategoryIds() != null){
                        List<Integer> categoryIds = ListUtils.stringToListAsInt(course.getCategoryIds(), ",");
                        List<CourseCategoryListedVo> categories = categoryIds.stream().map(categoryMap::get).collect(Collectors.toList());
                        courseListedVo.setCategories(categories);
                    }
                    courseListedVo.setCover(OSSUtil.completeUrl(course.getCover()));
                    return courseListedVo;
                })
                .collect(Collectors.toList());

    }
}
